import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:health_manager/common/routers/hm_router/adapter.dart';
import 'hm_router.dart';
import 'url_matcher.dart';

typedef URLPattern = String;
typedef URLOpenHandlerFactory = dynamic Function(
    String url, Map<String, dynamic> values, dynamic extra);
typedef URLOpenHandler = dynamic Function();

/// 导航器
class HMNavigator {
  HMNavigator._();

  /// 导航key（需要在HMRoutes.routerConfig中配置）
  GlobalKey<NavigatorState>? _navigatorKey;

  /// 全局上下文
  BuildContext get context {
    assert(_navigatorKey != null,
        'navigatorKey不能为空，你需要在HMRoutes.routerConfig中配置!');
    return _navigatorKey!.currentContext!;
  }

  /// 全局路由监听
  static final RouteObserver<Route<dynamic>> routeObserver = RouteObserver();

  /// 回调字典
  final _handlerFactories = <URLPattern, URLOpenHandlerFactory>{};

  /// url规则匹配（可扩展）
  final matcher = HMURLMatcher();

  /// 单例
  static final shared = HMNavigator._();

  /// method_name _handler
  /// description 回调闭包
  ///
  ///@param: url 完整url
  ///@param: extra  额外参数
  ///
  ///@return: URLOpenHandler?
  URLOpenHandler? _handler(String url, {extra}) {
    final urlPatterns = _handlerFactories.keys.toList();
    final result = matcher.match(url, urlPatterns);
    if (result == null) return null;
    final handle = _handlerFactories[result.pattern];
    if (handle == null) return null;
    return () => handle(url, result.values, extra);
  }

  /// method_name handle
  /// description 注册事件回调
  ///
  ///@param: pattern 完整url
  ///@param: URLOpenHandlerFactory 回调闭包
  ///
  void handle(URLPattern pattern, URLOpenHandlerFactory factory) {
    _handlerFactories[pattern] = factory;
  }

  /// method_name open
  /// description 调用事件
  ///
  ///@param: url 完整url
  ///@param: extra 额外参数
  ///
  ///@return: dynamic
  dynamic open(String url, {extra}) => _handler(url, extra: extra)?.call();

  /// 设置导航key
  static void setNavigatorKey(GlobalKey<NavigatorState> navigatorKey) {
    shared._navigatorKey = navigatorKey;
  }

  /// method_name go
  /// description 清空当前路由栈页面并跳新页面（需结合GoRouter使用）
  ///
  ///@param: path 路径
  ///@param: pathParameters 路径参数
  ///@param: queryParameters 请求参数
  ///@param: extra 额外参数
  static void go(
    String path, {
    Map<String, String> pathParameters = const <String, String>{},
    Map<String, dynamic> queryParameters = const <String, dynamic>{},
    Object? extra,
  }) {
    final toPath = path.urlValue?.path ?? "";
    return GoRouter.of(shared.context).goNamed(
      toPath,
      pathParameters: pathParameters,
      queryParameters: {...path.queryParameters, ...queryParameters},
      extra: extra,
    );
  }

  /// method_name push
  /// description push新页面（需结合GoRouter使用）
  ///
  ///@param: path 路径
  ///@param: pathParameters 路径参数
  ///@param: queryParameters 请求参数
  ///@param: extra 额外参数
  ///
  ///@return: Future<T?>?
  static Future<T?>? push<T extends Object?>(
    String path, {
    Map<String, String> pathParameters = const <String, String>{},
    Map<String, dynamic> queryParameters = const <String, dynamic>{},
    Object? extra,
  }) {
    final toPath = path.urlValue?.path ?? "";
    return GoRouter.of(shared.context).pushNamed(
      toPath,
      pathParameters: pathParameters,
      queryParameters: {...path.queryParameters, ...queryParameters},
      extra: extra,
    );
  }

  /// method_name pushReplacement
  /// description push并替换当前页面（需结合GoRouter使用）
  ///
  ///@param: path 路径
  ///@param: pathParameters 路径参数
  ///@param: queryParameters 请求参数
  ///@param: extra 额外参数
  ///@param: count 替换路由数
  ///
  ///@return: Future<T?>?
  static Future<T?> pushReplacement<T extends Object?>(
    String path, {
    Map<String, String> pathParameters = const <String, String>{},
    Map<String, dynamic> queryParameters = const <String, dynamic>{},
    Object? extra,
    int count = 1,
  }) {
    final toPath = path.urlValue?.path ?? "";
    final matches =
        GoRouter.of(shared.context).routerDelegate.currentConfiguration.matches;
    while (count > 1 && matches.length > 1) {
      matches.removeLast();
      count--;
    }
    return GoRouter.of(shared.context).pushReplacementNamed(
      toPath,
      pathParameters: pathParameters,
      queryParameters: {...path.queryParameters, ...queryParameters},
      extra: extra,
    );
  }

  /// method_name pushReplacement
  /// description 替换当前页面（需结合GoRouter使用）
  ///
  ///@param: path 路径
  ///@param: pathParameters 路径参数
  ///@param: queryParameters 请求参数
  ///@param: extra 额外参数
  ///
  ///@return: Future<T?>?
  static Future<T?> replace<T>(
    String path, {
    Map<String, String> pathParameters = const <String, String>{},
    Map<String, dynamic> queryParameters = const <String, dynamic>{},
    Object? extra,
  }) {
    final toPath = path.urlValue?.path ?? "";
    return GoRouter.of(shared.context).replaceNamed(
      toPath,
      pathParameters: pathParameters,
      queryParameters: {...path.queryParameters, ...queryParameters},
      extra: extra,
    );
  }

  /// 能否pop
  static bool canPop() => GoRouter.of(shared.context).canPop();

  /// method_name pop
  /// description pop栈顶页面
  ///
  ///@param: times pop次数
  ///@param: result 返回结果
  static void pop<T extends Object?>({int times = 1, T? result}) {
    FocusManager.instance.primaryFocus?.unfocus();
    while (times > 1) {
      if (canPop()) GoRouter.of(shared.context).pop();
      times--;
    }
    if (canPop()) GoRouter.of(shared.context).pop(result);
  }

  /// method_name popUntil
  /// description pop到指定路径
  ///
  ///@param: path 路径
  static void popUntil(String path) {
    final router = GoRouter.of(shared.context);
    var routes = router.routerDelegate.currentConfiguration.routes;
    var route = router.routerDelegate.currentConfiguration.routes.last;

    while (router.routerDelegate.canPop()) {
      final cIndex = routes.indexOf(route);

      if (routes.elementAt(cIndex - 1) is ShellRoute) {
        router.routerDelegate.currentConfiguration.matches.removeLast();
      }

      if (route is GoRoute) {
        if (path == route.path) break;
        if (!router.routerDelegate.canPop()) break;
        router.routerDelegate.pop();
      }
      routes = router.routerDelegate.currentConfiguration.routes;
      route = routes.last;
    }
  }

  /// method_name popRoot
  /// description pop到根页面
  ///
  ///@param: tabarPath 支持通过传递路由名称来切换tabbar，但只发出事件，具体切换需要监听该事件
  static void popRoot({String? tabarPath}) {
    FocusManager.instance.primaryFocus?.unfocus();
    while (canPop()) {
      GoRouter.of(shared.context).pop();
    }
    if (tabarPath != null) {
      HMNavigator.shared.open(HMRoutes.common.switchTabbar, extra: tabarPath);
    }
  }

  /// 路由栈
  static List<String> get routingStack {
    return GoRouter.of(shared.context)
        .routerDelegate
        .currentConfiguration
        .matches
        .map(
          (e) => e.matchedLocation,
        )
        .toList();
  }
}

extension HMNavigatorExt on String {
  /// method_name go
  /// description 清空当前路由栈页面并跳新页面（需结合GoRouter使用）
  ///
  ///@param: path 路径
  ///@param: pathParameters 路径参数
  ///@param: queryParameters 请求参数
  ///@param: extra 额外参数
  void go(
    String path, {
    Map<String, String> pathParameters = const <String, String>{},
    Map<String, dynamic> queryParameters = const <String, dynamic>{},
    Object? extra,
  }) {
    return HMNavigator.go(
      this,
      pathParameters: pathParameters,
      queryParameters: queryParameters,
      extra: extra,
    );
  }

  /// method_name push
  /// description push到当前页面
  ///
  ///@param: pathParameters 路径参数
  ///@param: queryParameters 请求参数
  ///@param: extra 额外参数
  ///
  ///@return: Future<T?>?
  Future<T?>? push<T extends Object?>({
    Map<String, String> pathParameters = const <String, String>{},
    Map<String, dynamic> queryParameters = const <String, dynamic>{},
    Object? extra,
  }) {
    return HMNavigator.push<T>(
      this,
      pathParameters: pathParameters,
      queryParameters: queryParameters,
      extra: extra,
    );
  }

  /// method_name pushReplacement
  /// description push并替换为当前页面
  ///
  ///@param: pathParameters 路径参数
  ///@param: queryParameters 请求参数
  ///@param: extra 额外参数
  ///@param: count 替换路由数
  ///
  ///@return: Future<T?>?
  Future<T?> pushReplacement<T extends Object?>({
    Map<String, String> pathParameters = const <String, String>{},
    Map<String, dynamic> queryParameters = const <String, dynamic>{},
    Object? extra,
    int count = 1,
  }) {
    return HMNavigator.pushReplacement<T>(
      this,
      pathParameters: pathParameters,
      queryParameters: queryParameters,
      extra: extra,
      count: count,
    );
  }

  /// method_name pushReplacement
  /// description 替换为当前页面
  ///
  ///@param: pathParameters 路径参数
  ///@param: queryParameters 请求参数
  ///@param: extra 额外参数
  ///
  ///@return: Future<T?>?
  Future<T?> replace<T>({
    Map<String, String> pathParameters = const <String, String>{},
    Map<String, dynamic> queryParameters = const <String, dynamic>{},
    Object? extra,
  }) {
    return HMNavigator.replace<T>(
      this,
      pathParameters: pathParameters,
      queryParameters: queryParameters,
      extra: extra,
    );
  }

  /// method_name popUntil
  /// description pop到当前路径
  void popUntil() {
    HMNavigator.popUntil(this);
  }
}
